﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;

namespace Yunchang.ILUI
{
    public class UIItem : UIController
    {
        public string resourcePath { get; set; }
        public int resourceID { get; set; }
        public bool inited { get; protected set; }
        public ILoadAsset loadAsset { get; set; }

        /// <summary>
        /// 打开参数
        /// </summary>
        public object mArg;

        protected LuaTable luaCtrl;
        protected Action<UIItem> OpenComplete = null;
        private RectTransform parent;

        /// <summary>
        /// 本item 的主干 ，所属的UIPage ， null 自己就是主干
        /// </summary>
        private UIItem parentItem = null;

        private List<UIItem> ItemList = new List<UIItem>();
        protected Canvas canvas = null;
        protected bool trunk = false;

        public void LoadAsset(RectTransform parent, Action<UIItem> OpenComplete)
        {
            this.parent = parent;
            this.OpenComplete = OpenComplete;
            OnLoadPage();
            LoadUIAsset(resourcePath, LoadComplete);
        }

        private void LoadComplete(GameObject obj)
        {
            OnInitAsset(obj, parent, true);
        }
        protected override void OnInitAsset(GameObject obj, RectTransform parent, bool positionRest)
        {
            base.OnInitAsset(obj, parent, positionRest);
            if (luaCtrl != null) InitLuaCtrl(luaCtrl);
            canvas = GetComponentFromParent<Canvas>(tranform);

            OnInit();

            if (OpenComplete != null)
                OpenComplete(this);
        }

        public override void OnTransformParentChanged()
        {
            base.OnTransformParentChanged();
            canvas = GetComponentFromParent<Canvas>(tranform);
        }

        #region lua
        private void InitLuaCtrl(LuaTable luaCtrl)
        {
            if (luaCtrl == null || uiMono == null) return;

            LuaTable monoTable = LuaManager.Ins.NewTable();
            string key;
            int valueCount = uiMono.valueList.Count;
            for (int i = 0, len = uiMono.keyList.Count; i < len; i++)
            {
                key = uiMono.keyList[i];
                if (string.IsNullOrEmpty(key)) continue;
                if (i >= valueCount || uiMono.valueList[i] == null)
                {
                    GLog.Error("【{0}】的UIMono中索引中的引用value丢失.或是key索引大于引用索引 ===>{1} ", signId, uiMono.name);
                    continue;
                }

                monoTable.Set(key, uiMono.valueList[i]);
            }
            luaCtrl.Set("mono", monoTable);
        }
        public void SetTalbeLua(LuaTable luaTable)
        {
            this.luaCtrl = luaTable;
            CallLua("InitTable", this.luaCtrl);
            luaCtrl.Set("this", this);
        }

        public void CallLua(string functionName)
        {
            CallLua(functionName, null);
        }
        public void CallLua(string functionName, object arg)
        {
            if (luaCtrl != null)
            {
                LuaFunction ac = luaCtrl.Get<LuaFunction>(functionName);
                if (ac != null) ac.Call(luaCtrl, arg);
            }
        }
        #endregion

        #region Add SubItem

        /// <summary>
        /// 添加一个UI子物件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj">挂载Item的空物体，obj上必须挂UIExtend脚本</param>
        public T AddExtend<T>(GameObject obj, object arg = null) where T : UIItem, new()
        {
            return AddExtend<T>(obj.GetComponent<UIExtend>(), arg);
        }

        /// <summary>
        /// 添加一个UI子物件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj">挂载Item的空物体，obj上必须挂UIExtend脚本</param>
        public T AddExtend<T>(UIExtend exten, object arg = null) where T : UIItem, new()
        {
            T item = new T();
            item.resourceID = exten.resourceID;
            item.mArg = arg;
            item.LoadAsset(exten.GetComponent<RectTransform>(), ItemAddComplete);

            return item;
        }

        public void AddExtend(GameObject obj)
        {
            UIExtend exten = obj.GetComponent<UIExtend>();
            AddExtend(exten);
        }
        public UIItem AddExtend(UIExtend exten)
        {
            if (exten == null) return null;
            UIItem item = new UIItem();
            item.resourceID = exten.resourceID;
            item.LoadAsset(exten.GetComponent<RectTransform>(), ItemAddComplete);

            return item;
        }

        /// <summary>
        /// 添加一个子物件
        /// </summary>
        /// <typeparam name="T"> 注意！ 返回的时候可能资源还没有加载完成，因为资源加载可能是异步的</typeparam>
        /// <param name="parent"></param>
        /// <param name="resourceID"></param>
        /// <returns></returns>
        public T AddItem<T>(RectTransform parent, int resourceID, object arg = null) where T : UIItem, new()
        {
            T item = new T();
            item.resourceID = resourceID;
            item.mArg = arg;
            item.LoadAsset(parent, ItemAddComplete);
            return item;
        }

        public void AddItem(Type type, RectTransform parent, int resourceID, object arg = null)
        {
            UIItem item = Activator.CreateInstance(type) as UIItem;
            if (item == null)
            {
                GLog.Error("AddItem Type error. typeName:{0} ", type.Name);
                return;
            }

            item.resourceID = resourceID;
            item.mArg = arg;
            item.LoadAsset(parent, ItemAddComplete);
        }
        /// <summary>
        /// 关联一个界面已有的mono物件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public T AddItem<T>(UIMono mono, object arg = null) where T : UIItem, new()
        {
            T item = new T();
            item.LoadComplete(mono.gameObject);
            item.mArg = arg;
            item.parent = mono.gameObject.GetComponent<RectTransform>();
            item.parentItem = this;
            ItemList.Add(item);
            return item;
        }

        /// <summary>
        /// 关联一个界面已有的mono物件
        /// </summary>
        /// <param name="type"></param>
        /// <param name="mono"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public UIItem AddItem(Type type, UIMono mono, params object[] args)
        {
            UIItem item = Activator.CreateInstance(type) as UIItem;
            if (item == null)
            {
                GLog.Error("AddItem Type error. typeName:{0} ", type.Name);
                return null;
            }

            item.LoadComplete(mono.gameObject);
            item.mArg = args;
            item.parent = mono.gameObject.GetComponent<RectTransform>();
            item.parentItem = this;
            ItemList.Add(item);
            return item;
        }

        /// <summary>
        /// 注意！ 返回的时候可能资源还没有加载完成，因为资源加载可能是异步的
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="resourceID"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public UIItem AddItem(RectTransform parent, int resourceID, Type type, params object[] args)
        {
            UIItem item = Activator.CreateInstance(type) as UIItem;
            item.resourceID = resourceID;
            item.mArg = args;
            item.LoadAsset(parent, ItemAddComplete);
            return item;
        }

        public void AddItem(RectTransform parent, int resourceID, LuaTable luaTable, params object[] args)
        {
            UIItem item = new UIItem();
            item.mArg = args;
            item.resourceID = resourceID;
            item.luaCtrl = luaTable;
            item.LoadAsset(parent, ItemAddComplete);
        }

        public T AddItemInstance<T>(GameObject itemObj, bool sortOrder = false) where T : UIItem, new()
        {
            T item = new T();
            item.OnInitAsset(itemObj, (RectTransform)itemObj.transform.parent, false);
            item.parentItem = this;
            ItemList.Add(item);

            if (sortOrder)
                InsertSortOrders(itemObj.transform.parent, item.uiMono.orderList);
            return item;
        }

        public T AddItemInstanceArgs<T>(GameObject itemObj, bool sortOrder, params object[] args)
            where T : UIItem, new()
        {
            return AddItemInstance<T>(itemObj, sortOrder, args);
        }

        public T AddItemInstance<T>(GameObject itemObj, bool sortOrder, object arg = null) where T : UIItem, new()
        {
            T item = new T();
            item.mArg = arg;
            item.OnInitAsset(itemObj, (RectTransform)itemObj.transform.parent, false);
            item.parentItem = this;
            ItemList.Add(item);
            if (sortOrder)
                InsertSortOrders(itemObj.transform.parent, item.uiMono.orderList);
            return item;
        }

        private void ItemAddComplete(UIItem item)
        {
            if (gameObject == null)
            {
                GameObject.Destroy(item.gameObject);
                return;
            }

            item.parentItem = this;
            ItemList.Add(item);
            ////if (item.orderList.Count > 0)
            ////    InsertSortOrders(item.parent, item.orderList);
            AddItemComplete(item);
        }

        protected void InsertSortOrders(Transform parent, List<UIOrder> tmpOrderList)
        {
            if (tmpOrderList == null) return;

            UIOrder parentOrder = GetComponentFromParent<UIOrder>(parent);
            UIItem trunk = GetTrunk(this);

            if (parentOrder == null || trunk == null) return;

            for (int i = 0; i < trunk.orderList.Count; i++)
            {
                if (trunk.orderList[i] == parentOrder)
                {
                    trunk.orderList.InsertRange(i + 1, tmpOrderList);
                    break;
                }
            }

            trunk.UpdateDepth();
        }
        public void InsertSortOrder(Transform parent, UIOrder uiOrder)
        {
            if (uiOrder == null) return;

            UIOrder parentOrder = GetComponentFromParent<UIOrder>(parent);
            UIItem trunk = GetTrunk(this);

            if (parentOrder == null || trunk == null) return;

            for (int i = 0; i < trunk.orderList.Count; i++)
            {
                if (trunk.orderList[i] == parentOrder)
                {
                    trunk.orderList.Insert(i + 1, uiOrder);
                    break;
                }
            }

            trunk.UpdateDepth();
        }


        public static void InsertSortOrder(UIItem item, Transform parent, UIOrder tmpSortOrder)
        {
            UIOrder parentOrder = GetComponentFromParent<UIOrder>(parent);
            UIItem trunk = GetTrunk(item);

            if (parentOrder == null || trunk == null) return;

            for (int i = 0; i < trunk.orderList.Count; i++)
            {
                if (trunk.orderList[i] == parentOrder)
                {
                    trunk.orderList.Insert(i + 1, tmpSortOrder);
                    break;
                }
            }

            trunk.UpdateDepth();
        }


        public void RemoveUIOrder(UIOrder uiOrder)
        {
            if (uiOrder == null) return;
            UIItem trunk = GetTrunk(this);
            trunk.orderList.Remove(uiOrder);
            trunk.UpdateDepth();
        }

        public virtual void UpdateDepth()
        {
        }
        #endregion

        #region static function
        public static UIItem GetTrunk(UIItem item)
        {
            return item.parent == null ? item : GetTrunk(item.parentItem);
        }

        public static T GetComponentFromParent<T>(Transform trans) where T : Component
        {
            if (trans == null) return null;
            T t = trans.GetComponent<T>();
            return t ?? null;
        }
        #endregion

        public void LoadUIAsset(string assetPath, Action<GameObject> loadComplete)
        {
            if (loadAsset == null)
            {
                GLog.Error("Need Imp ILoadAsset to Load UI Asset");
                if (loadComplete != null)
                {
                    loadComplete(null);
                }
                return;
            }
            loadAsset.LoadAsset(assetPath, loadComplete);
        }

        #region virtual
        /// <summary>
        /// 加载页面前
        /// </summary>
        protected virtual void OnLoadPage()
        {

        }
        protected virtual void OnInit()
        {
            inited = true;
            if (uiMono.needAwake)
               Awake();
            if (uiMono.needEnable)
               OnEnable();
        }
        /// <summary>
        /// 因为加载有可能是异步的所有需要一个回调
        /// </summary>
        /// <param name="item"></param>
        protected virtual void AddItemComplete(UIItem item)
        {
        }

        protected virtual void RemoveItem(UIItem item)
        {
            ItemList.Remove(item);
            GameObject.Destroy(item.gameObject);
        }
        #endregion

        #region CallLua

        /// <summary>
        /// 供上层初始化使用
        /// </summary>
        public override void Awake()
        {
            CallLua("Awake");
        }

        public override void Start()
        {
            CallLua("Start");
        }

        public override void OnEnable()
        {
            CallLua("OnEnable");
        }

        public override void OnDisable()
        {
            CallLua("OnDisable");
        }

        public virtual void OnExitScene()
        {
            CallLua("OnExitScene");

            if (ItemList != null && ItemList.Count > 0)
            {
                for (int i = 0; i < ItemList.Count; i++)
                {
                    ItemList[i].OnExitScene();
                }
            }
        }

        public virtual void OnEnterScene()
        {
            CallLua("OnEnterScene");

            if (ItemList != null && ItemList.Count > 0)
            {
                for (int i = 0; i < ItemList.Count; i++)
                {
                    ItemList[i].OnEnterScene();
                }
            }
        }

        public override void Update()
        {
            CallLua("Update");
            if (ItemList.Count > 0)
            {
                for (int i = 0; i < ItemList.Count; i++)
                {
                    if (ItemList[i] != null)
                        ItemList[i].Update();
                }
            }
        }

        public override void OnDestroy()
        {
            CallLua("OnDestroy");
            if (luaCtrl != null)
            {
                CallLua("ClearPage", luaCtrl);
            }

            mArg = null;
            ItemList = null;
            base.OnDestroy();
        }

        #endregion

        #region  xlua 用法

        public UIItem AddItemInstance(Type t, GameObject itemObj, bool sortOrder = false)
        {
            UIItem item = Activator.CreateInstance(t) as UIItem;
            item.OnInitAsset(itemObj, (RectTransform)itemObj.transform.parent, false);
            item.parentItem = this;
            ItemList.Add(item);

            //if (sortOrder)
            //    InsertSortOrders(itemObj.transform.parent, item.uiMono.orderList);

            return item;
        }
        #endregion
    }
}
